﻿using System;
using System.Collections.Generic;
using System.Text;
using RS.DOM.Common;
using RS.DOM.Construction;

namespace RS.DOM.Types
{
    public class Number : Token
    {
        #region Constructors

        public Number(Context context)
            : base(context)
        {
            base.TokenType = TokenType.Number;
        }

        public Number(Context context, int result)
            : base(context)
        {
            base.TokenType = TokenType.Number;
            base.Result = result;
        }

        #endregion

        #region Methods

        public override Token UnarOperation(OperationType type)
        {
            if (type == OperationType.Subtract)
            {
                this.Result = this.Result * (-1);
            }

            return this;
        }

        public override Token Operation(Token token, OperationType type)
        {
            if (type == OperationType.Plus)
            {
                return this.Plus(token);
            }
            else if (type == OperationType.PlusApply)
            {
                return this.PlusApply(token);
            }
            else if (type == OperationType.Multiply)
            {
                return this.Multiply(token);
            }
            else if (type == OperationType.Subtract)
            {
                return this.Subtract(token);
            }
            else if (type == OperationType.Devide)
            {
                return this.Devide(token);
            }
            else if (type == OperationType.Generate)
            {
                return this.Generate(token);
            }
            else if (type == OperationType.Dimension)
            {
                return this.Dimension(token);
            }
            else if (type == OperationType.Equal)
            {
                return this.Equal(token);
            }
            else if (type == OperationType.Add)
            {
                return this.Add(token);
            }
            else if (type == OperationType.Apply)
            {
                return this.Apply(token);
            }
            else if (type == OperationType.DoubleApply)
            {
                return this.DoubleApply(token);
            }
            else if (type == OperationType.Less)
            {
                return this.Less(token);
            }
            else if (type == OperationType.LessEqual)
            {
                return this.LessEqual(token);
            }
            else if (type == OperationType.DevideWithRest)
            {
                return this.DevideWithRest(token);
            }
            else if (type == OperationType.Great)
            {
                return this.Great(token);
            }
            else if (type == OperationType.Point)
            {
                return this.Point(token);
            }
            else if (type == OperationType.Rational)
            {
                return this.Rational(token);
            }
            else
            {
                return base.Operation(token, type);
            }
        }

        public Token Point(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                result = new Float(this.Context);
                result.Result = op1.Result + 0.1F * op2.Result;
            }

            return result;
        }

        public Token Rational(Token token)
        {
            Rational result = null;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                result = new Rational(this.Context);
                result.Result.Numerator = op1.Result;
                result.Result.Denominator = op2.Result;
            }

            return result;
        }

        public Token Plus(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                result = new Number(this.Context);
                result.Result = (int)this.Result + (int)token.Result;
            }
            else if (token.TokenType == TokenType.Float)
            {
                result = new Float(this.Context);
                result.Result = (int)this.Result + (float)token.Result;
            }

            return result;
        }

        public Token PlusApply(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                result.Result = (int)this.Result + (int)token.Result;
            }
            else if (token.TokenType == TokenType.Float)
            {
                result.Result = (int)this.Result + (float)token.Result;
            }

            return result;
        }

        public Token Multiply(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                result = new Number(this.Context);
                result.Result = (int)this.Result * (int)token.Result;
            }
            else if (token.TokenType == TokenType.Float)
            {
                result = new Float(this.Context);
                result.Result = (int)this.Result * (float)token.Result;
            }

            return result;
        }

        public Token Subtract(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                result = new Number(this.Context);
                result.Result = (int)this.Result - (int)token.Result;
            }
            else if (token.TokenType == TokenType.Float)
            {
                result = new Float(this.Context);
                result.Result = (int)this.Result - (float)token.Result;
            }

            return result;
        }

        public Token Devide(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                result = new Number(this.Context);
                result.Result = (int)this.Result / (int)token.Result;
            }
            else if (token.TokenType == TokenType.Float)
            {
                result = new Float(this.Context);
                result.Result = (int)this.Result / (float)token.Result;
            }

            return result;
        }

        public Token DevideWithRest(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                result = new Number(this.Context);
                result.Result = (int)this.Result % (int)token.Result;
            }
            else if (token.TokenType == TokenType.Collection)
            {
                Number op1 = this;
                Collection op2 = (Collection)token;

                for (int i = 0; i < op2.Result.Count; i++)
                {
                    op2.Result[i].Result = op1.Result % ((Number)op2.Result[i]).Result;
                }

                result = op2;
            }

            return result;
        }

        public Token Generate(Token token)
        {
            Collection result = null;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;
                result = new Collection(this.Context);

                if (op1.Result < op2.Result)
                {
                    for (int i = op1.Result; i <= op2.Result; i++)
                        result.Result.Add(new Number(this.Context, i));
                }
                else
                {
                    for (int i = op1.Result; i >= op2.Result; i--)
                        result.Result.Add(new Number(this.Context, i));
                }
            }

            return result;
        }

        public Token Dimension(Token token)
        {
            Token result = this;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                /*DocArea docArea = new DocArea();
                Area area = new Area(this.Context, docArea);
                area.Result.Create(op1.Result, op2.Result);*/

                Collections ncs = new Collections(this.Context);

                for (int i = 0; i < op2.Result; i++)
                {
                    Collection nc = new Collection(this.Context);

                    for (int j = 0; j < op1.Result; j++)
                    {
                        nc.Result.Add(new Number(this.Context, 0));
                    }

                    ncs.Result.Add(nc);
                }

                result = ncs;
            }

            return result;
        }

        public Token Equal(Token token)
        {
            Bool result = new Bool(this.Context, false);

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                if (op1.Result == op2.Result)
                    result = new Bool(this.Context, true);
            }

            return result;
        }

        public Token Add(Token token)
        {
            Collection result = null;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                result = new Collection(this.Context);

                result.Result.Add(op1);
                result.Result.Add(op2);
            }
            else if (token.TokenType == TokenType.Collection)
            {
                Number op1 = this;
                Collection op2 = (Collection)token;

                result = new Collection(this.Context);

                result.Result.Add(op1);
                result.Result.AddRange(op2.Result);
            }

            return result;
        }

        public Token Apply(Token token)
        {
            Number result = (Number)this;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                op1.Result = op2.Result;
                result = op1;
            }

            return result;
        }

        public Token DoubleApply(Token token)
        {
            Number result = (Number)this;

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                int tmp = op1.Result;
                op1.Result = op2.Result;
                op2.Result = tmp;

                result = op1;
            }

            return result;
        }

        public Token Less(Token token)
        {
            Bool result = new Bool(this.Context, false);

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                if (op1.Result < op2.Result)
                    result = new Bool(this.Context, true);
                else
                    result = new Bool(this.Context, false);
            }

            return result;
        }

        public Token LessEqual(Token token)
        {
            Bool result = new Bool(this.Context, false);

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                if (op1.Result <= op2.Result)
                    result = new Bool(this.Context, true);
                else
                    result = new Bool(this.Context, false);
            }

            return result;
        }

        public Token Great(Token token)
        {
            Bool result = new Bool(this.Context, false);

            if (token.TokenType == TokenType.Number)
            {
                Number op1 = this;
                Number op2 = (Number)token;

                if (op1.Result > op2.Result)
                    result = new Bool(this.Context, true);
                else
                    result = new Bool(this.Context, false);
            }

            return result;
        }

        public int Result
        {
            get
            {
                return (int)base.Result;
            }

            set
            {
                base.Result = value;
            }
        }

        public override Token Create()
        {
            return new Number(this.Context, this.Result);
        }

        public override string ToString()
        {
            return this.Result.ToString();
        }

        #endregion
    }
}
